mirror of
https://github.com/hwchase17/langchain.git
synced 2026-06-09 10:17:00 +00:00
ollama[patch]: support structured output (#28629)
- Bump minimum version of `ollama` to 0.4.4 (which also addresses
https://github.com/langchain-ai/langchain/issues/28607).
- Support recently-released [structured
output](https://ollama.com/blog/structured-outputs) feature. This can be
accessed by calling `.with_structured_output` with
`method="json_schema"` (choice of name
[mirrors](https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html#langchain_openai.chat_models.base.ChatOpenAI.with_structured_output)
what we have for OpenAI's structured output feature).
`ChatOllama` previously implemented `.with_structured_output` via the
[base
implementation](ec9b41431e/libs/core/langchain_core/language_models/chat_models.py (L1117)).
This commit is contained in:
@@ -4,10 +4,61 @@ from typing import List, Optional
|
||||
|
||||
import pytest
|
||||
from pydantic import BaseModel, Field
|
||||
from typing_extensions import Annotated, TypedDict
|
||||
|
||||
from langchain_ollama import ChatOllama
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("method"), [("function_calling"), ("json_schema")])
|
||||
def test_structured_output(method: str) -> None:
|
||||
"""Test to verify structured output via tool calling and ``format`` parameter."""
|
||||
|
||||
class Joke(BaseModel):
|
||||
"""Joke to tell user."""
|
||||
|
||||
setup: str = Field(description="question to set up a joke")
|
||||
punchline: str = Field(description="answer to resolve the joke")
|
||||
|
||||
llm = ChatOllama(model="llama3.1", temperature=0)
|
||||
query = "Tell me a joke about cats."
|
||||
|
||||
# Pydantic
|
||||
structured_llm = llm.with_structured_output(Joke, method=method) # type: ignore[arg-type]
|
||||
result = structured_llm.invoke(query)
|
||||
assert isinstance(result, Joke)
|
||||
|
||||
for chunk in structured_llm.stream(query):
|
||||
assert isinstance(chunk, Joke)
|
||||
|
||||
# JSON Schema
|
||||
structured_llm = llm.with_structured_output(Joke.model_json_schema(), method=method) # type: ignore[arg-type]
|
||||
result = structured_llm.invoke(query)
|
||||
assert isinstance(result, dict)
|
||||
assert set(result.keys()) == {"setup", "punchline"}
|
||||
|
||||
for chunk in structured_llm.stream(query):
|
||||
assert isinstance(chunk, dict)
|
||||
assert isinstance(chunk, dict) # for mypy
|
||||
assert set(chunk.keys()) == {"setup", "punchline"}
|
||||
|
||||
# Typed Dict
|
||||
class JokeSchema(TypedDict):
|
||||
"""Joke to tell user."""
|
||||
|
||||
setup: Annotated[str, "question to set up a joke"]
|
||||
punchline: Annotated[str, "answer to resolve the joke"]
|
||||
|
||||
structured_llm = llm.with_structured_output(JokeSchema, method=method) # type: ignore[arg-type]
|
||||
result = structured_llm.invoke(query)
|
||||
assert isinstance(result, dict)
|
||||
assert set(result.keys()) == {"setup", "punchline"}
|
||||
|
||||
for chunk in structured_llm.stream(query):
|
||||
assert isinstance(chunk, dict)
|
||||
assert isinstance(chunk, dict) # for mypy
|
||||
assert set(chunk.keys()) == {"setup", "punchline"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("model"), [("llama3.1")])
|
||||
def test_structured_output_deeply_nested(model: str) -> None:
|
||||
"""Test to verify structured output with a nested objects."""
|
||||
|
||||
Reference in New Issue
Block a user