reasoning display
This commit is contained in:
parent
b87c6539cb
commit
2407a8ab64
2 changed files with 21 additions and 188 deletions
|
|
@ -5,10 +5,6 @@ import streamlit as st
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
import anthropic
|
import anthropic
|
||||||
from dotenv import load_dotenv
|
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
|
# Model Constants
|
||||||
DEEPSEEK_MODEL: str = "deepseek-reasoner"
|
DEEPSEEK_MODEL: str = "deepseek-reasoner"
|
||||||
|
|
@ -40,45 +36,29 @@ class ModelChain:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.deepseek_messages.append({"role": "user", "content": user_input})
|
self.deepseek_messages.append({"role": "user", "content": user_input})
|
||||||
|
|
||||||
|
try:
|
||||||
response = self.deepseek_client.chat.completions.create(
|
response = self.deepseek_client.chat.completions.create(
|
||||||
|
max_tokens=1, # Keep max_tokens=1 to only get reasoning
|
||||||
model=DEEPSEEK_MODEL,
|
model=DEEPSEEK_MODEL,
|
||||||
max_tokens=1,
|
messages=self.deepseek_messages
|
||||||
messages=self.deepseek_messages,
|
|
||||||
stream=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
reasoning_content = ""
|
reasoning_content = response.choices[0].message.reasoning_content
|
||||||
final_content = ""
|
|
||||||
|
|
||||||
# Create expander for reasoning
|
# Create expander for reasoning
|
||||||
with st.expander("💭 Reasoning Process", expanded=True):
|
with st.expander("💭 Reasoning Process", expanded=True):
|
||||||
reasoning_placeholder = st.empty()
|
st.markdown(reasoning_content)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
elapsed_time = time.time() - start_time
|
elapsed_time = time.time() - start_time
|
||||||
time_str = f"{elapsed_time/60:.1f} minutes" if elapsed_time >= 60 else f"{elapsed_time:.1f} seconds"
|
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}")
|
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:
|
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 = {
|
user_message = {
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": [{"type": "text", "text": user_input}]
|
"content": [{"type": "text", "text": user_input}]
|
||||||
|
|
@ -106,16 +86,16 @@ class ModelChain:
|
||||||
full_response += text
|
full_response += text
|
||||||
response_placeholder.markdown(full_response)
|
response_placeholder.markdown(full_response)
|
||||||
|
|
||||||
|
# Store the messages in Claude's history only
|
||||||
self.claude_messages.extend([user_message, {
|
self.claude_messages.extend([user_message, {
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": [{"type": "text", "text": full_response}]
|
"content": [{"type": "text", "text": full_response}]
|
||||||
}])
|
}])
|
||||||
self.deepseek_messages.append({"role": "assistant", "content": full_response})
|
|
||||||
|
|
||||||
return full_response
|
return full_response
|
||||||
|
|
||||||
except Exception as e:
|
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"
|
return "Error occurred while getting response"
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
|
||||||
|
|
@ -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 <city_info> 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)
|
|
||||||
Loading…
Reference in a new issue