도구 사용(함수 호출)을 위한 스트리밍
도구 사용(함수 호출)을 위한 스트리밍
Cohere 플랫폼에서 도구 사용을 위한 스트리밍을 구현하는 방법과 이벤트 스트림에 대한 세부 정보를 다루는 가이드예요 (API v2).
출처: 문서
본문
개요(Overview)
도구 사용에서 응답 스트리밍을 활성화하려면 chat 대신 chat_stream 엔드포인트를 사용하세요.
도구 호출 단계와 응답 생성 단계 모두에서 응답을 스트리밍할 수 있어요. 이렇게 하면 모델이 도구 호출을 계획하고 실행하며 마지막으로 응답을 생성할 때 애플리케이션이 토큰 스트림을 받을 수 있습니다.
이벤트 스트림(Events stream)
도구 사용에서 엔드포인트가 스트리밍하는 이벤트는 기본 chat 스트림 이벤트의 구조를 따르지만, 관련 콘텐츠가 포함된 도구 호출과 응답 생성을 위한 추가 이벤트를 포함합니다. 이 섹션은 이벤트의 스트림과 그 내용을 설명해요.
도구 호출 단계(Tool calling step)
이벤트 유형(Event types)
message-start
기본 chat 스트림 이벤트와 동일해요.
tool-plan-delta
도구 계획(tool plan)의 다음 토큰이 생성될 때 내보내집니다.
tool-call-start
모델이 실행을 요구하는 도구 호출을 생성할 때 내보내집니다. 이 이벤트는 도구의 이름과 도구 호출 ID를 담고 있는 tool_calls 목록을 포함해요.
tool-call-delta
도구 호출의 다음 토큰이 생성될 때 내보내집니다.
tool-call-end
도구 호출이 끝났을 때 내보내집니다.
두 개 이상의 도구 호출이 이루어질 때(즉 병렬 도구 호출), tool-call-start, tool-call-delta, tool-call-end 이벤트의 시퀀스가 반복됩니다.
message-end
기본 chat 스트림 이벤트와 동일해요.
예제 스트림(Example stream)
다음은 도구 호출 단계의 예제 스트림이에요.
# User message
"What's the weather in Madrid and Brasilia?"
# Events stream
type='message-start' id='fba98ad3-e5a1-413c-a8de-84fbf9baabf7' delta=ChatMessageStartEventDelta(message=ChatMessageStartEventDeltaMessage(role='assistant', content=[], tool_plan='', tool_calls=[], citations=[]))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan='I'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' will'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' search'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' for'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' the'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' weather'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' in'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' Madrid'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' and'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan=' Brasilia'))
--------------------------------------------------
type='tool-plan-delta' delta=ChatToolPlanDeltaEventDelta(message=ChatToolPlanDeltaEventDeltaMessage(tool_plan='.'))
--------------------------------------------------
type='tool-call-start' index=0 delta=ChatToolCallStartEventDelta(message=ChatToolCallStartEventDeltaMessage(tool_calls=ToolCallV2(id='get_weather_p1t92w7gfgq7', type='function', function=ToolCallV2Function(name='get_weather', arguments=''))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='{\n "'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='location'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='":'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments=' "'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='Madrid'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='"'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='\n'))))
--------------------------------------------------
type='tool-call-delta' index=0 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='}'))))
--------------------------------------------------
type='tool-call-end' index=0
--------------------------------------------------
type='tool-call-start' index=1 delta=ChatToolCallStartEventDelta(message=ChatToolCallStartEventDeltaMessage(tool_calls=ToolCallV2(id='get_weather_ay6nmvjgp9vn', type='function', function=ToolCallV2Function(name='get_weather', arguments=''))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='{\n "'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='location'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='":'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments=' "'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='Bras'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='ilia'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='"'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='\n'))))
--------------------------------------------------
type='tool-call-delta' index=1 delta=ChatToolCallDeltaEventDelta(message=ChatToolCallDeltaEventDeltaMessage(tool_calls=ChatToolCallDeltaEventDeltaMessageToolCalls(function=ChatToolCallDeltaEventDeltaMessageToolCallsFunction(arguments='}'))))
--------------------------------------------------
type='tool-call-end' index=1
--------------------------------------------------
type='message-end' id=None delta=ChatMessageEndEventDelta(finish_reason='TOOL_CALL', usage=Usage(billed_units=UsageBilledUnits(input_tokens=37.0, output_tokens=28.0, search_units=None, classifications=None), tokens=UsageTokens(input_tokens=913.0, output_tokens=83.0)))
--------------------------------------------------
응답 생성 단계(Response generation step)
이벤트 유형(Event types)
message-start
기본 chat 스트림 이벤트와 동일해요.
content-start
기본 chat 스트림 이벤트와 동일합니다.
content-delta
기본 chat 스트림 이벤트와 동일해요.
citation-start
응답에서 생성된 인용마다 내보내집니다. 이 이벤트는 소스를 인용하는 텍스트의 start 및 end 인덱스, 해당 text, 그리고 sources 목록 같은 인용에 대한 세부 정보를 담고 있어요.
citation-end
인용의 끝을 나타내기 위해 내보내집니다. 생성된 인용이 여러 개라면, 이벤트는 citation-start와 citation-end 쌍의 연속으로 오게 됩니다.
content-end
기본 chat 스트림 이벤트와 동일해요.
message-end
기본 chat 스트림 이벤트와 동일합니다.
예제 스트림(Example stream)
다음은 응답 생성 단계의 예제 스트림이에요.
"What's the weather in Madrid and Brasilia?"
type='message-start' id='e8f9afc1-0888-46f0-a9ed-eb0e5a51e17f' delta=ChatMessageStartEventDelta(message=ChatMessageStartEventDeltaMessage(role='assistant', content=[], tool_plan='', tool_calls=[], citations=[]))
--------------------------------------------------
type='content-start' index=0 delta=ChatContentStartEventDelta(message=ChatContentStartEventDeltaMessage(content=ChatContentStartEventDeltaMessageContent(text='', type='text')))
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='It'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' is'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' currently'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' 2'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='4'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='°'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='C in'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' Madrid'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' and'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' 2'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='8'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='°'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='C in'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text=' Brasilia'))) logprobs=None
--------------------------------------------------
type='content-delta' index=0 delta=ChatContentDeltaEventDelta(message=ChatContentDeltaEventDeltaMessage(content=ChatContentDeltaEventDeltaMessageContent(text='.'))) logprobs=None
--------------------------------------------------
type='citation-start' index=0 delta=CitationStartEventDelta(message=CitationStartEventDeltaMessage(citations=Citation(start=16, end=20, text='24°C', sources=[ToolSource(type='tool', id='get_weather_m3kdvxncg1p8:0', tool_output={'temperature': '{"madrid":"24°C"}'})], type='TEXT_CONTENT')))
--------------------------------------------------
type='citation-end' index=0
--------------------------------------------------
type='citation-start' index=1 delta=CitationStartEventDelta(message=CitationStartEventDeltaMessage(citations=Citation(start=35, end=39, text='28°C', sources=[ToolSource(type='tool', id='get_weather_cfwfh3wzkbrs:0', tool_output={'temperature': '{"brasilia":"28°C"}'})], type='TEXT_CONTENT')))
--------------------------------------------------
type='citation-end' index=1
--------------------------------------------------
type='content-end' index=0
--------------------------------------------------
type='message-end' id=None delta=ChatMessageEndEventDelta(finish_reason='COMPLETE', usage=Usage(billed_units=UsageBilledUnits(input_tokens=87.0, output_tokens=19.0, search_units=None, classifications=None), tokens=UsageTokens(input_tokens=1061.0, output_tokens=85.0)))
--------------------------------------------------
사용 예시(Usage example)
이 섹션은 도구 사용 응답 생성 단계에서 스트리밍된 객체를 처리하는 예시를 제공해요.
설정(Setup)
먼저 Cohere 라이브러리를 임포트하고 클라이언트를 만듭니다.
Cohere 플랫폼
PYTHON
# ! pip install -U cohere
import cohere
co = cohere.ClientV2(
"COHERE_API_KEY"
) # Get your free API key here: https://dashboard.cohere.com/api-keys
프라이빗 배포(Private deployment)
PYTHON
# ! pip install -U cohere
import cohere
co = cohere.ClientV2(
api_key="", # Leave this blank
base_url="<YOUR_DEPLOYMENT_URL>",
)
도구 정의(Tool definition)
다음으로, 도구와 관련 스키마를 정의합니다.
PYTHON
def get_weather(location):
temperature = {
"bern": "22°C",
"madrid": "24°C",
"brasilia": "28°C",
}
loc = location.lower()
if loc in temperature:
return [{"temperature": {loc: temperature[loc]}}]
return [{"temperature": {loc: "Unknown"}}]
functions_map = {"get_weather": get_weather}
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "gets the weather of a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "the location to get the weather, example: San Francisco.",
}
},
"required": ["location"],
},
},
}
]
응답 스트리밍(Streaming the response)
응답을 스트리밍하기 전에 먼저 도구 호출과 실행 단계를 진행합니다.
PYTHON
messages = [
{
"role": "user",
"content": "What's the weather in Madrid and Brasilia?",
}
]
response = co.chat(
model="command-a-plus-05-2026", messages=messages, tools=tools
)
if response.message.tool_calls:
messages.append(response.message)
print(response.message.tool_plan, "\n")
print(response.message.tool_calls)
import json
if response.message.tool_calls:
for tc in response.message.tool_calls:
tool_result = functions_map[tc.function.name](
**json.loads(tc.function.arguments)
)
tool_content = []
for data in tool_result:
# Optional: the "document" object can take an "id" field for use in citations, otherwise auto-generated
tool_content.append(
{
"type": "document",
"document": {"data": json.dumps(data)},
}
)
messages.append(
{
"role": "tool",
"tool_call_id": tc.id,
"content": tool_content,
}
)
cURL
curl --request POST \
--url https://api.cohere.ai/v2/chat \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header "Authorization: bearer ***" \
--data '{
"model": "command-a-plus-05-2026",
"messages": [
{
"role": "user",
"content": "What'\''s the weather in Madrid and Brasilia?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "gets the weather of a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "the location to get the weather, example: San Francisco."
}
},
"required": ["location"]
}
}
}
]
}'
예제 응답:
I will use the get_weather tool to find the weather in Madrid and Brasilia.
[
ToolCallV2(
id="get_weather_15c2p6g19s8f",
type="function",
function=ToolCallV2Function(
name="get_weather", arguments='{"location":"Madrid"}'
),
),
ToolCallV2(
id="get_weather_n01pkywy0p2w",
type="function",
function=ToolCallV2Function(
name="get_weather", arguments='{"location":"Brasilia"}'
),
),
]
도구 결과를 받은 후에는 chat_stream 엔드포인트를 사용해 응답을 스트리밍할 수 있어요.
이벤트는 chunk 객체로 스트리밍됩니다. 아래 예시에서는 텍스트 응답을 표시하기 위해 content-delta를, 인용을 표시하기 위해 citation-start를 선택합니다.
PYTHON
response = co.chat_stream(
model="command-a-plus-05-2026", messages=messages, tools=tools
)
response_text = ""
citations = []
for chunk in response:
if chunk:
if chunk.type == "content-delta":
response_text += chunk.delta.message.content.text
print(chunk.delta.message.content.text, end="")
if chunk.type == "citation-start":
citations.append(chunk.delta.message.citations)
for citation in citations:
print(citation, "\n")
cURL
curl --request POST \
--url https://api.cohere.ai/v2/chat \
--header 'accept: text/event-stream' \
--header 'content-type: application/json' \
--header "Authorization: bearer ***" \
--data '{
"model": "command-a-plus-05-2026",
"messages": [
{
"role": "user",
"content": "What'\''s the weather in Madrid and Brasilia?"
},
{
"role": "assistant",
"tool_plan": "I will use the get_weather tool to find the weather in Madrid and Brasilia.",
"tool_calls": [
{
"id": "get_weather_15c2p6g19s8f",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Madrid\"}"
}
},
{
"id": "get_weather_n01pkywy0p2w",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Brasilia\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "get_weather_15c2p6g19s8f",
"content": [
{
"type": "document",
"document": {
"data": "{\"temperature\": {\"madrid\": \"24°C\"}}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "get_weather_n01pkywy0p2w",
"content": [
{
"type": "document",
"document": {
"data": "{\"temperature\": {\"brasilia\": \"28°C\"}}"
}
}
]
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "gets the weather of a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "the location to get the weather, example: San Francisco."
}
},
"required": ["location"]
}
}
}
],
"stream": true
}'
예제 응답:
It's currently 24°C in Madrid and 28°C in Brasilia.
start=5 end=9 text='24°C' sources=[ToolSource(type='tool', id='get_weather_15c2p6g19s8f:0', tool_output={'temperature': '{"madrid":"24°C"}'})] type='TEXT_CONTENT'
start=24 end=28 text='28°C' sources=[ToolSource(type='tool', id='get_weather_n01pkywy0p2w:0', tool_output={'temperature': '{"brasilia":"28°C"}'})] type='TEXT_CONTENT'