From 65516c65a3fc7098d343ba9c44e6e15a99b8f559 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Tue, 31 Mar 2026 15:00:11 +0800 Subject: [PATCH] Add zai-sdk dependency and update model references to glm-4.5-air --- backend/examples/cli_research.py | 2 +- backend/pyproject.toml | 1 + backend/src/agent/configuration.py | 6 ++--- backend/src/agent/graph.py | 32 +++++++++++++---------- backend/src/agent/prompts.py | 10 +++---- frontend/src/components/InputForm.tsx | 10 ++++++- frontend/src/components/WelcomeScreen.tsx | 2 +- 7 files changed, 36 insertions(+), 27 deletions(-) diff --git a/backend/examples/cli_research.py b/backend/examples/cli_research.py index efc1580..4ec2b92 100644 --- a/backend/examples/cli_research.py +++ b/backend/examples/cli_research.py @@ -21,7 +21,7 @@ def main() -> None: ) parser.add_argument( "--reasoning-model", - default="GLM-4.7", + default="glm-4.5-air", help="Model for the final answer", ) args = parser.parse_args() diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9a14e58..1b3c2d7 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -18,6 +18,7 @@ dependencies = [ "langgraph-api", "fastapi", "tavily-python", + "zai-sdk", ] diff --git a/backend/src/agent/configuration.py b/backend/src/agent/configuration.py index 8affba4..3fab3cf 100644 --- a/backend/src/agent/configuration.py +++ b/backend/src/agent/configuration.py @@ -9,21 +9,21 @@ class Configuration(BaseModel): """The configuration for the agent.""" query_generator_model: str = Field( - default="GLM-4.7", + default="glm-4.5-air", metadata={ "description": "The name of the language model to use for the agent's query generation." }, ) reflection_model: str = Field( - default="GLM-4.7", + default="glm-4.5-air", metadata={ "description": "The name of the language model to use for the agent's reflection." }, ) answer_model: str = Field( - default="GLM-4.7", + default="glm-4.5-air", metadata={ "description": "The name of the language model to use for the agent's answer." }, diff --git a/backend/src/agent/graph.py b/backend/src/agent/graph.py index d0956ac..ee9fb04 100644 --- a/backend/src/agent/graph.py +++ b/backend/src/agent/graph.py @@ -11,6 +11,7 @@ from langgraph.graph import START, END from langchain_core.runnables import RunnableConfig from langchain_openai import ChatOpenAI from tavily import TavilyClient +from zai import ZhipuAiClient from agent.state import ( OverallState, @@ -40,6 +41,7 @@ if os.getenv("TAVILY_API_KEY") is None: raise ValueError("TAVILY_API_KEY is not set") tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY")) +zhipu_client = ZhipuAiClient(api_key=os.getenv("OPENAI_API_KEY")) SchemaT = TypeVar("SchemaT", bound=BaseModel) @@ -73,13 +75,17 @@ def _extract_json_payload(content: str) -> str: def _invoke_json_model( - llm: ChatOpenAI, + model: str, prompt: str, schema: type[SchemaT], ) -> SchemaT: - """Invoke the model for JSON text and validate it with Pydantic.""" - result = llm.invoke(prompt) - content = result.content if isinstance(result.content, str) else str(result.content) + """Invoke the model via zai-sdk JSON mode and validate with Pydantic.""" + response = zhipu_client.chat.completions.create( + model=model, + messages=[{"role": "user", "content": prompt}], + response_format={"type": "json_object"}, + ) + content = response.choices[0].message.content json_payload = _extract_json_payload(content) try: @@ -93,22 +99,25 @@ def _invoke_json_model( def _supports_native_structured_output(model: str) -> bool: """Return whether the selected model should use LangChain structured output.""" normalized = model.strip().lower() - return normalized.startswith("glm-4.7") + return not normalized.startswith("glm") def _invoke_structured_model( - llm: ChatOpenAI, model: str, prompt: str, schema: type[SchemaT], ) -> SchemaT: - """Use native structured output when supported, otherwise fall back to JSON parsing.""" + """Use direct provider JSON mode for GLM, otherwise try native structured output.""" + if not _supports_native_structured_output(model): + return _invoke_json_model(model, prompt, schema) + if _supports_native_structured_output(model): try: + llm = create_llm(model, temperature=1.0) return llm.with_structured_output(schema).invoke(prompt) except ValueError: - return _invoke_json_model(llm, prompt, schema) - return _invoke_json_model(llm, prompt, schema) + return _invoke_json_model(model, prompt, schema) + return _invoke_json_model(model, prompt, schema) # Nodes @@ -130,8 +139,6 @@ def generate_query(state: OverallState, config: RunnableConfig) -> QueryGenerati if state.get("initial_search_query_count") is None: state["initial_search_query_count"] = configurable.number_of_initial_queries - llm = create_llm(configurable.query_generator_model, temperature=1.0) - current_date = get_current_date() formatted_prompt = query_writer_instructions.format( current_date=current_date, @@ -139,7 +146,6 @@ def generate_query(state: OverallState, config: RunnableConfig) -> QueryGenerati number_queries=state["initial_search_query_count"], ) result = _invoke_structured_model( - llm, configurable.query_generator_model, formatted_prompt, SearchQueryList, @@ -216,9 +222,7 @@ def reflection(state: OverallState, config: RunnableConfig) -> ReflectionState: research_topic=get_research_topic(state["messages"]), summaries="\n\n---\n\n".join(state["web_research_result"]), ) - llm = create_llm(reasoning_model, temperature=1.0) result = _invoke_structured_model( - llm, reasoning_model, formatted_prompt, Reflection, diff --git a/backend/src/agent/prompts.py b/backend/src/agent/prompts.py index fd5cc2e..7632b83 100644 --- a/backend/src/agent/prompts.py +++ b/backend/src/agent/prompts.py @@ -25,12 +25,10 @@ Format: Example: Topic: What revenue grew more last year apple stock or the number of people buying an iphone -```json {{ "rationale": "To answer this comparative growth question accurately, we need specific data points on Apple's stock performance and iPhone sales metrics. These queries target the precise financial information needed: company revenue trends, product-specific unit sales figures, and stock price movement over the same fiscal period for direct comparison.", "query": ["Apple total revenue growth fiscal year 2024", "iPhone unit sales growth fiscal year 2024", "Apple stock price growth fiscal year 2024"] }} -``` Context: {research_topic}""" @@ -67,13 +65,11 @@ Output Format: - "follow_up_queries": Write a specific question to address this gap Example: -```json {{ - "is_sufficient": true, // or false - "knowledge_gap": "The summary lacks information about performance metrics and benchmarks", // "" if is_sufficient is true - "follow_up_queries": ["What are typical performance benchmarks and metrics used to evaluate [specific technology]?"] // [] if is_sufficient is true + "is_sufficient": true, + "knowledge_gap": "", + "follow_up_queries": [] }} -``` Reflect carefully on the Summaries to identify knowledge gaps and produce a follow-up query. Then, produce your output following this JSON format: diff --git a/frontend/src/components/InputForm.tsx b/frontend/src/components/InputForm.tsx index 989ac86..d5bb367 100644 --- a/frontend/src/components/InputForm.tsx +++ b/frontend/src/components/InputForm.tsx @@ -26,7 +26,7 @@ export const InputForm: React.FC = ({ }) => { const [internalInputValue, setInternalInputValue] = useState(""); const [effort, setEffort] = useState("medium"); - const [model, setModel] = useState("GLM-4.7"); + const [model, setModel] = useState("glm-4.5-air"); const handleInternalSubmit = (e?: React.FormEvent) => { if (e) e.preventDefault(); @@ -135,6 +135,14 @@ export const InputForm: React.FC = ({ + +
+ glm-4.5-air +
+
= ({ />

- Powered by GLM-4.7, Tavily, and LangChain LangGraph. + Powered by glm-4.5-air, GLM-4.7, Tavily, and LangChain LangGraph.

);