import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Read api_key and other appetizers from environment variables
api_key = os.getenv('DASHSCOPE_API_KEY')
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
chat_model = "qwen-plus"
emb_model = "embedding-3"
from openai import Client
from pydantic import Field # Import Field for defining field metadata in Pydantic models
from llama_index.core.llms import ( CustomLLM, CompletionResponse, LLMMetadata,)
from llama_index.core.embeddings import BaseEmbedding
from llama_index.core.llms.callbacks import llm_completion_callback
from typing import List, Any, Generator
# Define OurLLM class, inheriting from CustomLLM base class
class OurLLM(CustomLLM): api_key: str = Field(default=api_key) base_url: str = Field(default=base_url) model_name: str = Field(default=chat_model) client: Client = Field(default=None, exclude=True) # Explicitly declare client field
def __init__(self, api_key: str, base_url: str, model_name: str = chat_model, **data: Any): super().__init__(**data) self.api_key = api_key self.base_url = base_url self.model_name = model_name self.client = Client(api_key=self.api_key, base_url=self.base_url) # Initialize client instance using passed api_key and base_url
@property def metadata(self) -> LLMMetadata: """Get LLM metadata.""" return LLMMetadata( model_name=self.model_name, ) @llm_completion_callback() def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse: response = self.client.chat.completions.create(model=self.model_name, messages=[{"role": "user", "content": prompt}]) if hasattr(response, 'choices') and len(response.choices) > 0: response_text = response.choices[0].message.content return CompletionResponse(text=response_text) else: raise Exception(f"Unexpected response format: {response}") @llm_completion_callback() def stream_complete( self, prompt: str, **kwargs: Any ) -> Generator[CompletionResponse, None, None]: response = self.client.chat.completions.create( model=self.model_name, messages=[{"role": "user", "content": prompt}], stream=True ) try: for chunk in response: chunk_message = chunk.choices[0].delta if not chunk_message.content: continue content = chunk_message.content yield CompletionResponse(text=content, delta=content) except Exception as e: raise Exception(f"Unexpected response format: {e}")
llm = OurLLM(api_key=api_key, base_url=base_url, model_name=chat_model)
response = llm.stream_complete("Who are you?")
for chunk in response: print(chunk, end="", flush=True)
I am a large-scale language model from Alibaba Cloud, called Tongyi Qianwen.
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
def multiply(a: float, b: float) -> float: """Multiply two numbers and returns the product""" return a * b
def add(a: float, b: float) -> float: """Add two numbers and returns the sum""" return a + b
def main():
multiply_tool = FunctionTool.from_defaults(fn=multiply)
add_tool = FunctionTool.from_defaults(fn=add)
response = agent.chat("What is 200 + (24 * 84) * 21? Use tools to calculate each step")
print(response)
> Running step ef75a574-3f5f-4b70-88f8-c11febe357f6. Step input: What is 200 + (24 * 84) * 21? Use tools to calculate each step
Thought: The current language of the user is: Chinese. I need to use a tool to help me answer the question.
Action: multiply
Action Input: {'a': 24, 'b': 84}
Observation: 2016
> Running step 8884dd41-d22f-469c-9afd-81613d03855c. Step input: None
Thought: I have the result of the multiplication. Next, I need to multiply this result by 21.
Action: multiply
Action Input: {'a': 2016, 'b': 21}
Observation: 42336
> Running step ec91d672-5fe2-4032-b6c7-5f80eb87b511. Step input: None
Thought: I have the result of the second multiplication. Now, I need to add 200 to this result.
Action: add
Action Input: {'a': 200, 'b': 42336}
Observation: 42536
> Running step 883497ad-b9ce-4732-8c77-2a6f4f470b67. Step input: None
Thought: I can answer without using any more tools. I'll use the user's language to answer.
Answer: 200 + (24 * 84) * 21 equals 42536. 200 + (24 * 84) * 21 equals 42536.
You can see that it prioritized using custom functions add and multiply to complete the calculations in the question, rather than relying on the large model. At the end, it summarized its thinking with “I can answer without using any more tools.” Interesting, right? We can customize part of the processing flow of the Agent, and besides using prompts, we have greater control.
Next, let’s customize a function for weather queries for the agent just created, and provide some fake data for return. (This is to review the custom knowledge points, not to call external tools for queries. Calling external tools will be mentioned in later articles.)
def get_weather(city: str) -> int: """ Gets the weather temperature of a specified city.
Args: city (str): The name or abbreviation of the city.
Returns: int: The temperature of the city. Returns 20 for 'NY' (New York), 30 for 'BJ' (Beijing), and -1 for unknown cities. """
# Convert the input city to uppercase to handle case-insensitive comparisons city = city.upper()
# Check if the city is New York ('NY') if city == "NY": return 20 # Return 20°C for New York
# Check if the city is Beijing ('BJ') elif city == "BJ": return 30 # Return 30°C for Beijing
# If the city is neither 'NY' nor 'BJ', return -1 to indicate unknown city else: return -1
weather_tool = FunctionTool.from_defaults(fn=get_weather)
In the main function, unlike the previous text, we added the weather_tool tool object.
agent = ReActAgent.from_tools([multiply_tool, add_tool, weather_tool], llm=llm, verbose=True)
Test the functionality! (Place this before the main function)
response = agent.chat("How is the weather in New York?")
print(response)
Its response is as follows:
> Running step e0002ada-fd52-44b9-9272-0fff7a4cb313. Step input: How is the weather in New York?
Thought: The current language of the user is: Chinese. I need to use a tool to help me answer the question.
Action: get_weather
Action Input: {'city': 'NY'}
Observation: 20
> Running step 81ea310a-3c35-4f92-9ed5-ee662394801b. Step input: None
Thought: I can answer without using any more tools. I'll use the user's language to answer.
Answer: The temperature in New York is 20 degrees.
You can see that the model’s reasoning ability is strong, as it called the function get_weather we defined, and completed the requirement of capitalizing the first letter of the city in the function’s prompt. Finally, it summarized the answer and output the result in natural language.
The ReActAgent realizes the possibility of automatically converting business into code, requiring only an API model to call, suitable for various business scenarios. In addition, LlamaIndex provides open-source tools, for more details, please refer to the official website.
Just a thought
Every agent is like an employee of a company, each with its own duties and unable to complete all tasks. Different agents are like different departments, each performing their roles and collaborating to complete complex tasks. Mastering the usage of different agents allows for combinatorial use to achieve different functionalities and improve control over LLMs.
Imitation, learning, and practical application are essential pathways for acquiring new knowledge. Don’t panic when encountering bugs; others have encountered similar errors. Search for solutions more, seek guidance from peers, and give yourself some patience. You will eventually run it through and learn it~
The rabbit’s mooncake factory (image source: internet)
Every little rabbit is like an agent, working together to make mooncakes.
This experience note is based on the Datawhale project “WowAgent” and contains no advertisements or related interests.
-End-
