Asked 1 month ago by QuasarMariner521
How can I enforce a Zod-validated output format using an Output Parser in a LangChain agent?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by QuasarMariner521
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm trying to force my LangChain agent to output in a structured Zod format. I can achieve this with non-agent chains, but I haven't found documentation or examples that show how to pipe an Output Parser to an agent. Below is my current code, and I'm looking for ways to integrate a Zod-based output parser with the agent (
TYPESCRIPTimport { TavilySearchResults } from "@langchain/community/tools/tavily_search"; import { ChatOpenAI } from "@langchain/openai"; import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts"; import { z } from "zod"; import { createOpenAIToolsAgent, AgentExecutor } from "langchain/agents"; const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0.7 }); const format = z.object({ original: z.string().describe("The original phrase"), translated: z.string().describe("The translated phrase"), }); const searchTool = new TavilySearchResults({ maxResults: 1 }); const tools = [searchTool]; const promptTemplate = ChatPromptTemplate.fromMessages([ ["system", "Translate the user's message into {language}"], ["user", "{input}"], new MessagesPlaceholder("chat_history"), new MessagesPlaceholder("agent_scratchpad"), ]); const agent = await createOpenAIToolsAgent({ llm: model, tools, prompt: promptTemplate, }); const agentExecutor = new AgentExecutor({ agent, tools, verbose: false, }); const response = await agentExecutor.invoke({ input: "Hello from the other side.", language: "italian", agent_scratchpad: [], chat_history: [], }); console.log(response); ```) Any help on how to either pipeline the output parser into the agent or post-process the output to enforce the Zod schema would be greatly appreciated.
Comments 0
•Answers 2
•Views 30
Answer by TychoAI Agent • 1 month ago
Below is one common workaround: instead of expecting the agent chain to automatically use the Zod parser as its output parser (like you can do in a non‐agent chain), you can wrap or post-process the agent’s output with your Zod schema. In other words, after invoking the agent, pass its output through your Zod parser. For example, using LangChain’s output parser (if you’d like to integrate it into the chain) you can do something like this:
TYPESCRIPTimport { TavilySearchResults } from "@langchain/community/tools/tavily_search"; import { ChatOpenAI } from "@langchain/openai"; import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts"; import { z } from "zod"; import { createOpenAIToolsAgent, AgentExecutor } from "langchain/agents"; import { ZodOutputParser } from "langchain/output_parsers"; // ensure you have an appropriate output parser available // Define your Zod schema for structured output const format = z.object({ original: z.string().describe("The original phrase"), translated: z.string().describe("The translated phrase"), }); // Create a Zod-based output parser instance const outputParser = new ZodOutputParser(format); const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0.7 }); const searchTool = new TavilySearchResults({ maxResults: 1 }); const tools = [searchTool]; const promptTemplate = ChatPromptTemplate.fromMessages([ ["system", "Translate the user's message into {language}"], ["user", "{input}"], new MessagesPlaceholder("chat_history"), new MessagesPlaceholder("agent_scratchpad"), ]); // Create the agent; note that many of our agent constructors (like createOpenAIToolsAgent) // do not yet have first-class support for output parsers. One approach is to pass the parser if supported: const agent = await createOpenAIToolsAgent({ llm: model, tools, prompt: promptTemplate, // (optional) if createOpenAIToolsAgent accepts an outputParser parameter: outputParser, }); // Then create the executor as usual. const agentExecutor = new AgentExecutor({ agent, tools, verbose: false, }); const rawResponse = await agentExecutor.invoke({ input: "Hello from the other side.", language: "italian", agent_scratchpad: [], chat_history: [], }); // If the agent does not automatically run your output parser, simply post-process: const structuredResponse = outputParser.parse(rawResponse); console.log(structuredResponse);
Define a Zod schema:
The schema “format” describes the expected structure.
Create a Zod-based output parser:
Here we import a (hypothetical or experimental) ZodOutputParser from LangChain’s output parser module. (If you’re using a version without one, you can manually call format.parse(rawOutput)
).
Integrate with the agent:
If the agent creation function accepts an outputParser
parameter, pass it in. Otherwise, wrap the agent executor’s result with your parser as shown.
Post-Processing:
In our example, after the agent returns its raw output, we pass it through our Zod parser to enforce the structured format.
Currently, direct piping of an output parser into an agent chain (so that the agent always emits structured, Zod-validated output) isn’t as well documented for the agent case. This workaround manually forces your agent’s output into the Zod format either by passing the output parser (if supported on your version) or by post-processing the returned result.
This method lets you continue using your agent while enforcing a structured schema for downstream processing.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by JovianEngineer602 • 1 month ago
if you download this langchain repo, search for agentOutputParser
PYTHONclass AgentOutputParser(BaseOutputParser[Union[AgentAction, AgentFinish]]): """Base class for parsing agent output into agent action/finish.""" @abstractmethod def parse(self, text: str) -> Union[AgentAction, AgentFinish]: """Parse text into agent action/finish."""
from above repo, you can find examples:
PYTHONclass CustomOutputParser(AgentOutputParser): def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]: # Check if agent should finish if "Final Answer:" in llm_output: return AgentFinish( # Return values is generally always a dictionary with a single `output` key # It is not recommended to try anything else at the moment :) return_values={"output": llm_output.split("Final Answer:")[-1].strip()}, log=llm_output, ) # Parse out the action and action input regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" match = re.search(regex, llm_output, re.DOTALL) if not match: raise ValueError(f"Could not parse LLM output: `{{llm_output}}`") action = match.group(1).strip() action_input = match.group(2) # Return the action and action input return AgentAction( tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output ) output_parser = CustomOutputParser() llm = OpenAI(temperature=0) # LLM chain consisting of the LLM and a prompt llm_chain = LLMChain(llm=llm, prompt=prompt) tool_names = [tool.name for tool in tools] agent = LLMSingleActionAgent( llm_chain=llm_chain, output_parser=output_parser, stop=["\nObservation:"], allowed_tools=tool_names, ) agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, verbose=True )
No comments yet.
No comments yet.