Compare commits

..

No commits in common. "9b253617819a26fe74ad179d581997b3b82669ef" and "a176dcac521c0b3c68ed70f34f1ee8040d7641b9" have entirely different histories.

4 changed files with 12 additions and 41 deletions

1
.gitignore vendored
View file

@ -1,5 +1,4 @@
.idea/ .idea/
workspace/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/

View file

@ -13,8 +13,6 @@ services:
build: build:
context: . context: .
target: development target: development
tags:
- mrkan0/lambda-agent:dev
additional_contexts: additional_contexts:
agent_api: ${AGENT_API_PATH} agent_api: ${AGENT_API_PATH}
volumes: volumes:

View file

@ -1,10 +1,7 @@
from typing import AsyncIterator from typing import AsyncIterator
from src.agent.base import create_agent from src.agent.base import create_agent
from lambda_agent_api.server import (
AgentEventUnion, MsgEventTextChunk, MsgEventToolCallChunk,
MsgEventToolResult, MsgEventEnd
)
class AgentService: class AgentService:
_instance = None _instance = None
@ -16,44 +13,21 @@ class AgentService:
cls._instance._thread_id = "default" cls._instance._thread_id = "default"
return cls._instance return cls._instance
async def astream(self, text: str) -> AsyncIterator[AgentEventUnion]: async def astream(self, text: str) -> AsyncIterator[str]:
config = {"configurable": {"thread_id": self._thread_id}} config = {"configurable": {"thread_id": self._thread_id}}
# Используем astream_events для перехвата детальных событий (инструменты, чанки и т.д.) async for event in self._agent.astream(
async for event in self._agent.astream_events(
{"messages": [{"role": "user", "content": text}]}, {"messages": [{"role": "user", "content": text}]},
config=config, config=config,
version="v2" # Обязательно v2 для современных версий LangChain
): ):
kind = event["event"] messages = event.get("messages") or event.get("model", {}).get(
"messages", []
# 1. Агент генерирует токены (текст или аргументы для инструмента) )
if kind == "on_chat_model_stream": if messages:
chunk = event["data"]["chunk"] last_msg = messages[-1]
content = getattr(last_msg, "content", None)
# Если генерируется обычный текст if isinstance(content, str) and content.strip():
if chunk.content: yield content
yield MsgEventTextChunk(text=chunk.content)
# Если агент решил использовать инструмент (Langchain выдает tool_call_chunks)
if hasattr(chunk, "tool_call_chunks") and chunk.tool_call_chunks:
for tool_chunk in chunk.tool_call_chunks:
yield MsgEventToolCallChunk(
tool_name=tool_chunk.get("name"),
args_chunk=tool_chunk.get("args")
)
# 2. Инструмент завершил работу и вернул результат
elif kind == "on_tool_end":
yield MsgEventToolResult(
tool_name=event["name"],
result=event["data"].get("output")
)
# 3. В конце генерации отправляем событие завершения
yield MsgEventEnd(tokens_used=0) # потом заменить на метадату
def get_agent_service() -> AgentService: def get_agent_service() -> AgentService:

View file

@ -40,5 +40,5 @@ async def process_message(ws: WebSocket, msg, agent_service: AgentService):
match msg: match msg:
case MsgUserMessage(): case MsgUserMessage():
async for chunk in agent_service.astream(msg.text): async for chunk in agent_service.astream(msg.text):
await ws.send_text(chunk.model_dump_json()) await ws.send_text(MsgEventTextChunk(text=chunk).model_dump_json())
await ws.send_text(MsgEventEnd(tokens_used=0).model_dump_json()) await ws.send_text(MsgEventEnd(tokens_used=0).model_dump_json())