llama-index
130 строк · 4.0 Кб
1# ReAct agent formatter
2
3import logging4from abc import abstractmethod5from typing import List, Optional, Sequence6
7from llama_index.legacy.agent.react.prompts import (8CONTEXT_REACT_CHAT_SYSTEM_HEADER,9REACT_CHAT_SYSTEM_HEADER,10)
11from llama_index.legacy.agent.react.types import (12BaseReasoningStep,13ObservationReasoningStep,14)
15from llama_index.legacy.bridge.pydantic import BaseModel16from llama_index.legacy.core.llms.types import ChatMessage, MessageRole17from llama_index.legacy.tools import BaseTool18
19logger = logging.getLogger(__name__)20
21
22def get_react_tool_descriptions(tools: Sequence[BaseTool]) -> List[str]:23"""Tool."""24tool_descs = []25for tool in tools:26tool_desc = (27f"> Tool Name: {tool.metadata.name}\n"28f"Tool Description: {tool.metadata.description}\n"29f"Tool Args: {tool.metadata.fn_schema_str}\n"30)31tool_descs.append(tool_desc)32return tool_descs33
34
35# TODO: come up with better name
36class BaseAgentChatFormatter(BaseModel):37"""Base chat formatter."""38
39class Config:40arbitrary_types_allowed = True41
42@abstractmethod43def format(44self,45tools: Sequence[BaseTool],46chat_history: List[ChatMessage],47current_reasoning: Optional[List[BaseReasoningStep]] = None,48) -> List[ChatMessage]:49"""Format chat history into list of ChatMessage."""50
51
52class ReActChatFormatter(BaseAgentChatFormatter):53"""ReAct chat formatter."""54
55system_header: str = REACT_CHAT_SYSTEM_HEADER # default56context: str = "" # not needed w/ default57
58def format(59self,60tools: Sequence[BaseTool],61chat_history: List[ChatMessage],62current_reasoning: Optional[List[BaseReasoningStep]] = None,63) -> List[ChatMessage]:64"""Format chat history into list of ChatMessage."""65current_reasoning = current_reasoning or []66
67format_args = {68"tool_desc": "\n".join(get_react_tool_descriptions(tools)),69"tool_names": ", ".join([tool.metadata.get_name() for tool in tools]),70}71if self.context:72format_args["context"] = self.context73
74fmt_sys_header = self.system_header.format(**format_args)75
76# format reasoning history as alternating user and assistant messages77# where the assistant messages are thoughts and actions and the user78# messages are observations79reasoning_history = []80for reasoning_step in current_reasoning:81if isinstance(reasoning_step, ObservationReasoningStep):82message = ChatMessage(83role=MessageRole.USER,84content=reasoning_step.get_content(),85)86else:87message = ChatMessage(88role=MessageRole.ASSISTANT,89content=reasoning_step.get_content(),90)91reasoning_history.append(message)92
93return [94ChatMessage(role=MessageRole.SYSTEM, content=fmt_sys_header),95*chat_history,96*reasoning_history,97]98
99@classmethod100def from_defaults(101cls,102system_header: Optional[str] = None,103context: Optional[str] = None,104) -> "ReActChatFormatter":105"""Create ReActChatFormatter from defaults."""106if not system_header:107system_header = (108REACT_CHAT_SYSTEM_HEADER
109if not context110else CONTEXT_REACT_CHAT_SYSTEM_HEADER111)112
113return ReActChatFormatter(114system_header=system_header,115context=context or "",116)117
118@classmethod119def from_context(cls, context: str) -> "ReActChatFormatter":120"""Create ReActChatFormatter from context.121
122NOTE: deprecated
123
124"""
125logger.warning(126"ReActChatFormatter.from_context is deprecated, please use `from_defaults` instead."127)128return ReActChatFormatter.from_defaults(129system_header=CONTEXT_REACT_CHAT_SYSTEM_HEADER, context=context130)131