From 2407a8ab6414448175d2873f0d777ab558dd0f45 Mon Sep 17 00:00:00 2001 From: Madhu Date: Tue, 28 Jan 2025 23:40:47 +0530 Subject: [PATCH] reasoning display --- .../ai_r1-tooluse-langroid/main.py | 62 +++----- .../ai_r1-tooluse-langroid/test.py | 147 ------------------ 2 files changed, 21 insertions(+), 188 deletions(-) delete mode 100644 ai_agent_tutorials/ai_r1-tooluse-langroid/test.py diff --git a/ai_agent_tutorials/ai_r1-tooluse-langroid/main.py b/ai_agent_tutorials/ai_r1-tooluse-langroid/main.py index e94023f..3a294f8 100644 --- a/ai_agent_tutorials/ai_r1-tooluse-langroid/main.py +++ b/ai_agent_tutorials/ai_r1-tooluse-langroid/main.py @@ -5,10 +5,6 @@ import streamlit as st from openai import OpenAI import anthropic from dotenv import load_dotenv -from rich import print as rprint -from rich.panel import Panel -from prompt_toolkit import PromptSession -from prompt_toolkit.styles import Style # Model Constants DEEPSEEK_MODEL: str = "deepseek-reasoner" @@ -36,49 +32,33 @@ class ModelChain: def get_model_display_name(self): return self.current_model - def get_deepseek_reasoning(self, user_input: str) -> str: + def get_deepseek_reasoning(self, user_input: str) -> str: start_time = time.time() self.deepseek_messages.append({"role": "user", "content": user_input}) - response = self.deepseek_client.chat.completions.create( - model=DEEPSEEK_MODEL, - max_tokens=1, - messages=self.deepseek_messages, - stream=True - ) - - reasoning_content = "" - final_content = "" - - # Create expander for reasoning - with st.expander("💭 Reasoning Process", expanded=True): - reasoning_placeholder = st.empty() + try: + response = self.deepseek_client.chat.completions.create( + max_tokens=1, # Keep max_tokens=1 to only get reasoning + model=DEEPSEEK_MODEL, + messages=self.deepseek_messages + ) - for chunk in response: - if chunk.choices[0].delta.reasoning_content: - reasoning_piece = chunk.choices[0].delta.reasoning_content - reasoning_content += reasoning_piece - reasoning_placeholder.markdown(reasoning_content) - elif chunk.choices[0].delta.content: - final_content += chunk.choices[0].delta.content + reasoning_content = response.choices[0].message.reasoning_content + + # Create expander for reasoning + with st.expander("💭 Reasoning Process", expanded=True): + st.markdown(reasoning_content) + elapsed_time = time.time() - start_time + time_str = f"{elapsed_time/60:.1f} minutes" if elapsed_time >= 60 else f"{elapsed_time:.1f} seconds" + st.caption(f"⏱️ Thought for {time_str}") - elapsed_time = time.time() - start_time - time_str = f"{elapsed_time/60:.1f} minutes" if elapsed_time >= 60 else f"{elapsed_time:.1f} seconds" - st.caption(f"⏱️ Thought for {time_str}") + return reasoning_content - return reasoning_content + except Exception as e: + st.error(f"Error getting DeepSeek reasoning: {str(e)}") + return "Error occurred while getting reasoning" def get_claude_response(self, user_input: str, reasoning: str) -> str: - """ - Get response from Claude model. - - Args: - user_input: User's input text - reasoning: Reasoning from DeepSeek - - Returns: - str: Claude's response - """ user_message = { "role": "user", "content": [{"type": "text", "text": user_input}] @@ -106,16 +86,16 @@ class ModelChain: full_response += text response_placeholder.markdown(full_response) + # Store the messages in Claude's history only self.claude_messages.extend([user_message, { "role": "assistant", "content": [{"type": "text", "text": full_response}] }]) - self.deepseek_messages.append({"role": "assistant", "content": full_response}) return full_response except Exception as e: - st.error(f"Error in response: {str(e)}") + st.error(f"Error in Claude response: {str(e)}") return "Error occurred while getting response" def main() -> None: diff --git a/ai_agent_tutorials/ai_r1-tooluse-langroid/test.py b/ai_agent_tutorials/ai_r1-tooluse-langroid/test.py deleted file mode 100644 index 0350d0d..0000000 --- a/ai_agent_tutorials/ai_r1-tooluse-langroid/test.py +++ /dev/null @@ -1,147 +0,0 @@ - -import os -from typing import List -import fire - -from langroid.pydantic_v1 import BaseModel, Field -import langroid as lr -from langroid.utils.configuration import settings -from langroid.agent.tool_message import ToolMessage -from langroid.agent.tools.orchestration import FinalResultTool -import langroid.language_models as lm -from rich.prompt import Prompt -from langroid.agent.chat_document import ChatDocument - -# for best results: -DEFAULT_LLM = lm.OpenAIChatModel.GPT4o - -os.environ["TOKENIZERS_PARALLELISM"] = "false" - -# (1) Define the desired structure via Pydantic. -# Here we define a nested structure for City information. -# The "Field" annotations are optional, and are included in the system message -# if provided, and help with generation accuracy. - - -class CityData(BaseModel): - population: int = Field(..., description="population of city") - country: str = Field(..., description="country of city") - - -class City(BaseModel): - name: str = Field(..., description="name of city") - details: CityData = Field(..., description="details of city") - - -# (2) Define the Tool class for the LLM to use, to produce the above structure. -class CityTool(lr.agent.ToolMessage): - """Present information about a city""" - - request: str = "city_tool" - purpose: str = """ - To present AFTER user gives a city name, - with all fields of the appropriate type filled out; - """ - city_info: City = Field(..., description="information about a city") - - def handle(self) -> FinalResultTool: - """Handle LLM's structured output if it matches City structure""" - print("SUCCESS! Got Valid City Info") - return FinalResultTool(answer=self.city_info) - - @staticmethod - def handle_message_fallback( - agent: lr.ChatAgent, msg: str | ChatDocument - ) -> str | None: - """ - We end up here when there was no recognized tool msg from the LLM; - In this case use the AgentDoneTool with content set to - the original message content. - """ - if isinstance(msg, ChatDocument) and msg.metadata.sender == lr.Entity.LLM: - return f""" - You forgot to use the TOOL/Function `{CityTool.name()}`. - Please use this tool to present the city info. - """ - - @classmethod - def examples(cls) -> List["ToolMessage"]: - # Used to provide few-shot examples in the system prompt - return [ - cls( - city_info=City( - name="San Francisco", - details=CityData( - population=800_000, - country="USA", - ), - ) - ) - ] - - -def app( - m: str = DEFAULT_LLM, # model - d: bool = False, # pass -d to enable debug mode (see prompts etc) - nc: bool = False, # pass -nc to disable cache-retrieval (i.e. get fresh answers) -): - settings.debug = d - settings.cache = not nc - # create LLM config - llm_cfg = lm.OpenAIGPTConfig( - chat_model=m or DEFAULT_LLM, - chat_context_length=32000, # set this based on model - max_output_tokens=1000, - temperature=0.2, - stream=True, - timeout=45, - ) - - # Recommended: First test if basic chat works with this llm setup as below: - # Once this works, then you can try the rest of the example. - # - # agent = lr.ChatAgent( - # lr.ChatAgentConfig( - # llm=llm_cfg, - # ) - # ) - # - # agent.llm_response("What is 3 + 4?") - # - # task = lr.Task(agent) - # verify you can interact with this in a chat loop on cmd line: - # task.run("Concisely answer some questions") - - # Define a ChatAgentConfig and ChatAgent - - config = lr.ChatAgentConfig( - llm=llm_cfg, - system_message=f""" - You will receive a city name, - and you must use the TOOL/FUNCTION `{CityTool.name()}` to generate/present - information about the city. - """, - ) - - agent = lr.ChatAgent(config) - - # (4) Enable the Tool for this agent --> this auto-inserts JSON instructions - # and few-shot examples (specified in the tool defn above) into the system message - agent.enable_message(CityTool) - - # (5) Create task specialized to return City object - task: City | None = lr.Task(agent, interactive=False)[City] - - while True: - city = Prompt.ask("Enter a city name") - if city in ["q", "x"]: - break - result: City | None = task.run(city) - if result: - print(f"City Info: {result}") - else: - print("No valid city info found.") - - -if __name__ == "__main__": - fire.Fire(app) \ No newline at end of file