Agentes de IA são máquinas de estado e não dangs
As máquinas de sintetizadoras permitem que os usuários criem e executem as máquinas de estado do agente de IA ( Synth ), fornecendo uma SynthDefinition para definir um fluxo de trabalho de IA estruturado.
As máquinas de estado são uma construção poderosa, pois permitem que um especialista em domínio desconstrua o problema em conjuntos de estados e transições.
As transições entre os estados podem chamar um LLM, ferramenta, processo de dados ou uma mistura de muitas saídas.
Instale o pacote. pip install synth_machine[openai,togetherai,anthropic] ou poetry add synth_machine[openai,togetherai,anthropic]
Adicione as chaves do ambiente do seu provedor de API para as quais
# You only need to set the API providers you want to use.
export OPENAI_API_KUY=secret
export ANTHROPIC_API_KEY=secret
export TOGETHER_API_KEY=secret
pip install synth_machine[vllm,llamacpp] ou poetry add synth_machine[vllm,llamacpp]
Você provavelmente precisará configurar CUDA, VLLM ou LLAMA.CPP para uso local.
Links úteis:
agent = Synth(
config: dict[SynthDefinition], # Synth state machine defining states, transitions and prompts.
tools=[], # List of tools the agent will use
memory={}, # Any existing memory to add on top of any model_config.initial_memory
rag_runner: Optional[RAG] = None # Define a RAG integration for your agent.
postprocess_functions = [] # Any glue code functions
store : ObjectStore = ObjectStore(":memory:") # Any files created by tools will automatically go to you object store
A SynthDefinition pode ser encontrada nos documentos SynthDefinition ou synth_machine/synth_definition.py. Os modelos de base pydantic que compõem SynthDefinition serão a representação mais precisa de um Synth .
Esperamos que a especificação tenha atualizações entre as principais versões.
A qualquer momento, você pode verificar o estado atual e os próximos gatilhos
# Check state
agent.current_state()
# Triggers
agent.interfaces_for_available_triggers()
await agent.trigger(
"[trigger_name]",
params={
"input_1": "hello"
}
)
As chamadas de transição em lote gerarão qualquer variável de saída gerada nessa transição.
await agent.streaming_trigger(
"[trigger_name]",
params={
"input_1": "hello"
}
)
As respostas de streaming produzem qualquer um dos seguintes eventos:
class YieldTasks(StrEnum):
CHUNK = "CHUNK"
MODEL_CONFIG = "MODEL_CONFIG"
SET_MEMORY = "SET_MEMORY"
SET_ACTIVE_OUTPUT = "SET_ACTIVE_OUTPUT"
CHUNK : as gerações LLM são enviadas por pedaços de um token de cada vez.MODEL_CONFIG : Gosta de que o Executor está sendo usado atualmente para qualquer interfaces de front -end específica do provedor.SET_MEMORP : envia eventos que configuram novas variáveis de memóriaSET_ACTIVE_OUTPUT : produz o gatilho de saída de transição atual. Isso permite que os usuários experimentem usando trigger e, em seguida, se integrem às gerações LLM de fluxo em tempo real aos usuários usando eventos laterais do servidor (SSE) e trigger_streaming .
Oferecemos vários executores para gerar conclusões de bate -papo Local ou API LLM.
openai : https://openai.com/api/pricing/togetherai : https://docs.together.ai/docs/inference-modelsanthropic : https://docs.anthrópico.com/en/docs/models-overviewgoogle : https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/overview VLLM : https://github.com/vllm-project/vllmLlama-CPP : https://github.com/ggerganov/llama.cpp Model Config Você pode especificar o provedor e o modelo no default-model-config e na base de sintetizador ou model_config na saída de transição.
ModelConfig:
...
executor: [openai|togetherai|anthropic|vllm|llamacpp]
llm_name: [model_name]
A memória do agente é um dicionário que contém todas as variáveis intermediárias cria em estados anteriores e entradas humanas / do sistema.
agent.memory
# -> {
# "[memory_key]": [memory_value]
# }
As funções pós -processo devem ser usadas apenas para o código básico de cola, todas as principais funcionalidades devem ser incorporadas em ferramentas.
Vá para "./tools/tofuTool/api.py para visualizar a funcionalidade.
Inicie a API
cd tools/tofuTool
poetry install
poetry run uvicorn api:app --port=5001 --reload
Recuperar a API Spec
curl -X GET http://localhost:5001/openapi.json > openapi_schema.json
Defina a ferramenta
Você pode definir uma ferramenta como tal com apenas o nome, o terminal da API e o esquema de abertura da ferramenta.
tofu_tool = Tool(
name="tofu_tool",
api_endpoint="http://localhost:5001",
api_spec=tool_spec
)
A geração de recuperação de recuperação é uma ferramenta poderosa para melhorar as respostas do LLM, fornecendo exemplos ou exercícios semanticamente semelhantes ao material que o LLM está tentando gerar.
synth_machine é de forma flexível, desde que você herde de synth_machine.RAG e crie:
embed(documents: List[str]) equery(prompt: str, rag_config: Optional[synth_machine.RAGConfig])É fácil integrar vários provedores e bancos de dados de vetores. Com o tempo, será suportado e as implementações de RAG da comunidade em uma ampla variedade de provedores de incorporação e bancos de dados de vetores.
A aula de pano a seguir é ideal para experimentar configurações locais de pano na CPU.
pip install qdrant-client, fastembed
Defina aula de pano
from synth_machine.rag import RAG
from qdrant_client import AsyncQdrantClient
from fastembed import TextEmbedding
from typing import List, Optional
from qdrant_client.models import Distance, VectorParams, PointStruct
class Qdrant(RAG):
"""
VectorDB: Qdrant - https://github.com/qdrant/qdrant
Embeddings: FastEmbed - https://github.com/qdrant/fastembed
This provides fast and lightweight on-device CPU embeddings creation and
similarity search using Qdrant in memory.
"""
def __init__(
self,
collection_name: str,
embedding_model: str="BAAI/bge-small-en-v1.5",
embedding_dimensions: int=384,
embedding_threads: int=-1,
qdrant_location: str=":memory:",
):
self.embedding_model = TextEmbedding(
model_name=embedding_model,
threads=embedding_threads
)
self.embedding_dimensions = embedding_dimensions
self.qdrant = AsyncQdrantClient(qdrant_location)
self.collection_name = collection_name
async def create_collection(self) -> bool:
if await self.qdrant.collection_exists(self.collection_name):
return True
else:
return await self.qdrant.create_collection(
collection_name=self.collection_name,
vectors_config=VectorParams(
size=self.embedding_dimensions, # maps to 'BAAI/bge-small-en-v1.5' model dimensions
distance=Distance.COSINE
)
)
async def embed(self, documents: List[str], metadata: Optional[List[dict]]=None):
if metadata and len(documents) != len(metadata):
raise ValueError("documents and metadata must be the same length")
embedding_list = list(
self.embedding_model.embed(documents)
)
upsert_response = await self.qdrant.upsert(
collection_name=self.collection_name,
points=[
PointStruct(
id=i,
vector=list(vector),
payload=metadata[i]
)
for i, vector in enumerate(embedding_list)
]
)
return upsert_response.status
async def query(self, prompt: str, rag_config: RAGConfig) -> List[dict]:
embedding = next(self.embedding_model.embed([prompt]))
similar_responses = await self.qdrant.search(
collection_name=self.collection_name,
query_vector=embedding,
limit=rag_config.n
)
return [
point.payload for point in similar_responses
]
Agora inicie a classe QDRANT e forneça ao definir Synth .
qdrant = Qdrant(collection_name="tofu_examples")
await qdrant.create_collection()
agent = Synth(
...
rag_runner=Qdrant
)
As ferramentas podem retornar uma variedade de objetos diferentes. Qualquer arquivo criado por uma ferramenta irá automaticamente para o seu agent.store . Usamos o ObjectStore para armazenamento de arquivos, com ObjectStore(":memory:") como o padrão.
Para recuperar um arquivo: agent.store.get(file_name)
ObjectStore, permitindo fácil integração para:
from synth_machine.machine import ObjectStore
agent = Agent(
...
store=ObjectStore("gs://[bucket_name]/[prefix]))
)
Qualquer funcionalidade personalizada pode ser definida como uma função definida pelo usuário (UDF).
Estes tomam Synth.memory como entrada e permite executar a funcionalidade personalizada como parte da synth-machine .
# Define postprocess function
from synth_machine.user_defined_functions import udf
@udf
def abc_postprocesss(memory):
...
return memory["variable_key"]
agent = Synth(
...
user_defined_functions = {
"abc": abc_postprocess
}
)
...
- key: trigger_udf
inputs:
- key: variable_key
outputs:
- key: example_udf
udf: abc
Nota: Qualquer funcionalidade não trivial deve ser uma ferramenta e não UDF.