Skip to content

Commit

Permalink
Changed ollama version to incorporate tool calling
Browse files Browse the repository at this point in the history
  • Loading branch information
Sathvik Ravi authored and Sathvik Ravi committed Oct 5, 2024
1 parent ca83bee commit 3f7b758
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging
import os
import json
from typing import Collection
from opentelemetry.instrumentation.ollama.config import Config
from opentelemetry.instrumentation.ollama.utils import dont_throw
Expand Down Expand Up @@ -57,6 +58,61 @@ def _set_span_attribute(span, name, value):
return


def _set_prompts(span, messages):
if not span.is_recording() or messages is None:
return
for i, msg in enumerate(messages):
prefix = f"{SpanAttributes.LLM_PROMPTS}.{i}"

_set_span_attribute(span, f"{prefix}.role", msg.get("role"))
if msg.get("content"):
content = msg.get("content")
if isinstance(content, list):
content = json.dumps(content)
_set_span_attribute(span, f"{prefix}.content", content)
if msg.get("tool_call_id"):
_set_span_attribute(span, f"{prefix}.tool_call_id", msg.get("tool_call_id"))
tool_calls = msg.get("tool_calls")
if tool_calls:
for i, tool_call in enumerate(tool_calls):
function = tool_call.get("function")
_set_span_attribute(
span,
f"{prefix}.tool_calls.{i}.id",
tool_call.get("id"),
)
_set_span_attribute(
span,
f"{prefix}.tool_calls.{i}.name",
function.get("name"),
)
_set_span_attribute(
span,
f"{prefix}.tool_calls.{i}.arguments",
function.get("arguments"),
)

if function.get("arguments"):
function["arguments"] = json.loads(function.get("arguments"))


def set_tools_attributes(span, tools):
if not tools:
return

for i, tool in enumerate(tools):
function = tool.get("function")
if not function:
continue

prefix = f"{SpanAttributes.LLM_REQUEST_FUNCTIONS}.{i}"
_set_span_attribute(span, f"{prefix}.name", function.get("name"))
_set_span_attribute(span, f"{prefix}.description", function.get("description"))
_set_span_attribute(
span, f"{prefix}.parameters", json.dumps(function.get("parameters"))
)


@dont_throw
def _set_input_attributes(span, llm_request_type, kwargs):
_set_span_attribute(span, SpanAttributes.LLM_REQUEST_MODEL, kwargs.get("model"))
Expand All @@ -78,6 +134,9 @@ def _set_input_attributes(span, llm_request_type, kwargs):
f"{SpanAttributes.LLM_PROMPTS}.{index}.role",
message.get("role"),
)
_set_prompts(span, kwargs.get("messages"))
if kwargs.get("tools"):
set_tools_attributes(span, kwargs.get("tools"))
else:
_set_span_attribute(span, f"{SpanAttributes.LLM_PROMPTS}.0.role", "user")
_set_span_attribute(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ opentelemetry-instrumentation = "^0.48b0"
opentelemetry-semantic-conventions = "^0.48b0"
opentelemetry-semantic-conventions-ai = "0.4.1"

ollama = "^0.2.0"
ollama = "^0.3.2"
[tool.poetry.group.dev.dependencies]
autopep8 = "^2.2.0"
flake8 = "7.0.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
interactions:
- request:
body: '{"model": "llama3.1", "messages": [{"role": "assistant", "content": "",
"tool_calls": [{"function": {"name": "get_current_weather", "arguments": {"location":
"San Francisco"}}}]}, {"role": "tool", "content": "The weather in San Francisco
is 70 degrees and sunny."}], "tools": [], "stream": false, "format": "", "options":
{}, "keep_alive": null}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '345'
content-type:
- application/json
host:
- 127.0.0.1:11434
user-agent:
- ollama-python/0.3.2 (arm64 darwin) Python/3.12.4
method: POST
uri: http://127.0.0.1:11434/api/chat
response:
body:
string: '{"model":"llama3.1","created_at":"2024-09-16T02:41:57.128675Z","message":{"role":"assistant","content":"This
is a simple example, but in a real-world scenario, you would need to have
an API key to access the OpenWeatherMap API. You can get one for free on their
website. Also, this code should be placed in a file and run from there instead
of running it directly in the Python interpreter. \n\nNote: This is just a
simple example, in real-world scenarios, you would need to handle errors more
robustly and potentially add more features such as getting weather data for
multiple locations at once or handling different units (e.g., Celsius)."},"done_reason":"stop","done":true,"total_duration":6037504209,"load_duration":28126292,"prompt_eval_count":44,"prompt_eval_duration":182953000,"eval_count":113,"eval_duration":5825102000}'
headers:
Content-Length:
- '830'
Content-Type:
- application/json; charset=utf-8
Date:
- Mon, 16 Sep 2024 02:41:57 GMT
status:
code: 200
message: OK
version: 1
48 changes: 48 additions & 0 deletions packages/opentelemetry-instrumentation-ollama/tests/test_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,54 @@ def test_ollama_chat(exporter):
)


@pytest.mark.vcr
def test_ollama_chat_tool_calls(exporter):
ollama.chat(
model="llama3.1",
messages=[
{
'role': 'assistant',
'content': '',
'tool_calls': [{
'function': {
'name': 'get_current_weather',
'arguments': '{"location": "San Francisco"}'
}
}]
},
{
'role': 'tool',
'content': 'The weather in San Francisco is 70 degrees and sunny.'
}
],
)

spans = exporter.get_finished_spans()
ollama_span = spans[0]

assert ollama_span.name == "ollama.chat"
assert ollama_span.attributes.get(f"{SpanAttributes.LLM_SYSTEM}") == "Ollama"
assert ollama_span.attributes.get(f"{SpanAttributes.LLM_REQUEST_TYPE}") == "chat"
assert not ollama_span.attributes.get(f"{SpanAttributes.LLM_IS_STREAMING}")
assert ollama_span.attributes.get(f"{SpanAttributes.LLM_REQUEST_MODEL}") == "llama3.1"
assert f"{SpanAttributes.LLM_REQUEST_FUNCTIONS}.0.content" not in ollama_span.attributes
assert (
ollama_span.attributes[f"{SpanAttributes.LLM_PROMPTS}.0.tool_calls.0.name"]
== "get_current_weather"
)
assert (
ollama_span.attributes[
f"{SpanAttributes.LLM_PROMPTS}.0.tool_calls.0.arguments"
]
== '{"location": "San Francisco"}'
)

assert (
ollama_span.attributes[f"{SpanAttributes.LLM_PROMPTS}.1.content"]
== "The weather in San Francisco is 70 degrees and sunny."
)


@pytest.mark.vcr
def test_ollama_streaming_chat(exporter):
gen = ollama.chat(
Expand Down

0 comments on commit 3f7b758

Please sign in to comment.