mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-19 21:33:51 +00:00
langchain-ollama (partners) / langchain-core: allow passing ChatMessages to Ollama (including arbitrary roles) (#30411)
Replacement for PR #30191 (@ccurme) **Description**: currently, ChatOllama [will raise a value error if a ChatMessage is passed to it](https://github.com/langchain-ai/langchain/blob/master/libs/partners/ollama/langchain_ollama/chat_models.py#L514), as described https://github.com/langchain-ai/langchain/pull/30147#issuecomment-2708932481. Furthermore, ollama-python is removing the limitations on valid roles that can be passed through chat messages to a model in ollama - https://github.com/ollama/ollama-python/pull/462#event-16917810634. This PR removes the role limitations imposed by langchain and enables passing langchain ChatMessages with arbitrary 'role' values through the langchain ChatOllama class to the underlying ollama-python Client. As this PR relies on [merged but unreleased functionality in ollama-python]( https://github.com/ollama/ollama-python/pull/462#event-16917810634), I have temporarily pointed the ollama package source to the main branch of the ollama-python github repo. Format, lint, and tests of new functionality passing. Need to resolve issue with recently added ChatOllama tests. (Now resolved) **Issue**: resolves #30122 (related to ollama issue https://github.com/ollama/ollama/issues/8955) **Dependencies**: no new dependencies [x] PR title [x] PR message [x] Lint and test: format, lint, and test all running successfully and passing --------- Co-authored-by: Ryan Stewart <ryanstewart@Ryans-MacBook-Pro.local> Co-authored-by: Chester Curme <chester.curme@gmail.com>
This commit is contained in:
parent
0c723af4b0
commit
dbf9986d44
@ -61,7 +61,9 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "72ee0c4b-9764-423a-9dbf-95129e185210",
|
||||
"metadata": {},
|
||||
"source": "To enable automated tracing of your model calls, set your [LangSmith](https://docs.smith.langchain.com/) API key:"
|
||||
"source": [
|
||||
"To enable automated tracing of your model calls, set your [LangSmith](https://docs.smith.langchain.com/) API key:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@ -98,7 +100,9 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "b18bd692076f7cf7",
|
||||
"metadata": {},
|
||||
"source": "Make sure you're using the latest Ollama version for structured outputs. Update by running:"
|
||||
"source": [
|
||||
"Make sure you're using the latest Ollama version for structured outputs. Update by running:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@ -106,7 +110,9 @@
|
||||
"id": "b7a05cba95644c2e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": "%pip install -U ollama"
|
||||
"source": [
|
||||
"%pip install -U ollama"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@ -438,6 +444,63 @@
|
||||
"print(query_chain)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fb6a331f-1507-411f-89e5-c4d598154f3c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Reasoning models and custom message roles\n",
|
||||
"\n",
|
||||
"Some models, such as IBM's [Granite 3.2](https://ollama.com/library/granite3.2), support custom message roles to enable thinking processes.\n",
|
||||
"\n",
|
||||
"To access Granite 3.2's thinking features, pass a message with a `\"control\"` role with content set to `\"thinking\"`. Because `\"control\"` is a non-standard message role, we can use a [ChatMessage](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.chat.ChatMessage.html) object to implement it:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "d7309fa7-990e-4c20-b1f0-b155624ecf37",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Here is my thought process:\n",
|
||||
"This question is asking for the result of 3 raised to the power of 3, which is a basic mathematical operation. \n",
|
||||
"\n",
|
||||
"Here is my response:\n",
|
||||
"The expression 3^3 means 3 raised to the power of 3. To calculate this, you multiply the base number (3) by itself as many times as its exponent (3):\n",
|
||||
"\n",
|
||||
"3 * 3 * 3 = 27\n",
|
||||
"\n",
|
||||
"So, 3^3 equals 27.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_core.messages import ChatMessage, HumanMessage\n",
|
||||
"from langchain_ollama import ChatOllama\n",
|
||||
"\n",
|
||||
"llm = ChatOllama(model=\"granite3.2:8b\")\n",
|
||||
"\n",
|
||||
"messages = [\n",
|
||||
" ChatMessage(role=\"control\", content=\"thinking\"),\n",
|
||||
" HumanMessage(\"What is 3^3?\"),\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"response = llm.invoke(messages)\n",
|
||||
"print(response.content)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6271d032-da40-44d4-9b52-58370e164be3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that the model exposes its thought process in addition to its final response."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3a5bb5ca-c3ae-4a58-be67-2cd18574b9a3",
|
||||
@ -465,7 +528,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.4"
|
||||
"version": "3.10.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
@ -26,6 +26,7 @@ from langchain_core.messages import (
|
||||
AIMessageChunk,
|
||||
BaseMessage,
|
||||
BaseMessageChunk,
|
||||
ChatMessage,
|
||||
HumanMessage,
|
||||
SystemMessage,
|
||||
ToolCall,
|
||||
@ -511,7 +512,7 @@ class ChatOllama(BaseChatModel):
|
||||
) -> Sequence[Message]:
|
||||
ollama_messages: list = []
|
||||
for message in messages:
|
||||
role: Literal["user", "assistant", "system", "tool"]
|
||||
role: str
|
||||
tool_call_id: Optional[str] = None
|
||||
tool_calls: Optional[list[dict[str, Any]]] = None
|
||||
if isinstance(message, HumanMessage):
|
||||
@ -528,6 +529,8 @@ class ChatOllama(BaseChatModel):
|
||||
)
|
||||
elif isinstance(message, SystemMessage):
|
||||
role = "system"
|
||||
elif isinstance(message, ChatMessage):
|
||||
role = message.role
|
||||
elif isinstance(message, ToolMessage):
|
||||
role = "tool"
|
||||
tool_call_id = message.tool_call_id
|
||||
|
@ -6,7 +6,10 @@ build-backend = "pdm.backend"
|
||||
authors = []
|
||||
license = { text = "MIT" }
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = ["ollama<1,>=0.4.4", "langchain-core<1.0.0,>=0.3.52"]
|
||||
dependencies = [
|
||||
"ollama>=0.4.8,<1.0.0",
|
||||
"langchain-core<1.0.0,>=0.3.52",
|
||||
]
|
||||
name = "langchain-ollama"
|
||||
version = "0.3.2"
|
||||
description = "An integration package connecting Ollama and LangChain"
|
||||
|
@ -1,7 +1,13 @@
|
||||
"""Test chat model integration."""
|
||||
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from httpx import Client, Request, Response
|
||||
from langchain_core.messages import ChatMessage
|
||||
from langchain_tests.unit_tests import ChatModelUnitTests
|
||||
|
||||
from langchain_ollama.chat_models import ChatOllama, _parse_arguments_from_tool_call
|
||||
@ -23,3 +29,38 @@ def test__parse_arguments_from_tool_call() -> None:
|
||||
response = _parse_arguments_from_tool_call(raw_tool_calls[0])
|
||||
assert response is not None
|
||||
assert isinstance(response["arg_1"], str)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _mock_httpx_client_stream(
|
||||
*args: Any, **kwargs: Any
|
||||
) -> Generator[Response, Any, Any]:
|
||||
yield Response(
|
||||
status_code=200,
|
||||
content='{"message": {"role": "assistant", "content": "The meaning ..."}}',
|
||||
request=Request(method="POST", url="http://whocares:11434"),
|
||||
)
|
||||
|
||||
|
||||
def test_arbitrary_roles_accepted_in_chatmessages(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setattr(Client, "stream", _mock_httpx_client_stream)
|
||||
|
||||
llm = ChatOllama(
|
||||
base_url="http://whocares:11434",
|
||||
model="granite3.2",
|
||||
verbose=True,
|
||||
format=None,
|
||||
)
|
||||
|
||||
messages = [
|
||||
ChatMessage(
|
||||
role="somerandomrole",
|
||||
content="I'm ok with you adding any role message now!",
|
||||
),
|
||||
ChatMessage(role="control", content="thinking"),
|
||||
ChatMessage(role="user", content="What is the meaning of life?"),
|
||||
]
|
||||
|
||||
llm.invoke(messages)
|
||||
|
@ -288,7 +288,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.3.52"
|
||||
version = "0.3.54"
|
||||
source = { editable = "../../core" }
|
||||
dependencies = [
|
||||
{ name = "jsonpatch" },
|
||||
@ -381,7 +381,7 @@ typing = [
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "langchain-core", editable = "../../core" },
|
||||
{ name = "ollama", specifier = ">=0.4.4,<1" },
|
||||
{ name = "ollama", specifier = ">=0.4.8,<1.0.0" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
@ -405,7 +405,7 @@ typing = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-tests"
|
||||
version = "0.3.18"
|
||||
version = "0.3.19"
|
||||
source = { editable = "../../standard-tests" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
@ -625,15 +625,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "ollama"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b0/6d/dc77539c735bbed5d0c873fb029fb86aa9f0163df169b34152914331c369/ollama-0.4.7.tar.gz", hash = "sha256:891dcbe54f55397d82d289c459de0ea897e103b86a3f1fad0fdb1895922a75ff", size = 12843 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e2/64/709dc99030f8f46ec552f0a7da73bbdcc2da58666abfec4742ccdb2e800e/ollama-0.4.8.tar.gz", hash = "sha256:1121439d49b96fa8339842965d0616eba5deb9f8c790786cdf4c0b3df4833802", size = 12972 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/31/83/c3ffac86906c10184c88c2e916460806b072a2cfe34cdcaf3a0c0e836d39/ollama-0.4.7-py3-none-any.whl", hash = "sha256:85505663cca67a83707be5fb3aeff0ea72e67846cea5985529d8eca4366564a1", size = 13210 },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/3f/164de150e983b3a16e8bf3d4355625e51a357e7b3b1deebe9cc1f7cb9af8/ollama-0.4.8-py3-none-any.whl", hash = "sha256:04312af2c5e72449aaebac4a2776f52ef010877c554103419d3f36066fe8af4c", size = 13325 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
Loading…
Reference in New Issue
Block a user