Build a LangChain Agent for AlifOffice


LangChain agents can use any REST API as a tool. This guide wires the AlifOffice API into a LangChain agent so you can query and update your workspace with natural language.


Setup


bash
pip install langchain langchain-openai requests
export OPENAI_API_KEY=sk-...
export AO_API_KEY=ao_...
export AO_WORKSPACE=your-workspace

Define the Tools


python
import os, json, requests
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_functions_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

AO_BASE    = "https://alifoffice.com/api/v1"
AO_HEADERS = {
    "Authorization": f"Bearer {os.environ['AO_API_KEY']}",
    "X-Workspace":   os.environ["AO_WORKSPACE"],
    "Content-Type":  "application/json",
}

def ao_get(path: str, params: dict = None) -> dict:
    return requests.get(f"{AO_BASE}/{path}", headers=AO_HEADERS, params=params).json()

def ao_post(path: str, body: dict) -> dict:
    return requests.post(f"{AO_BASE}/{path}", headers=AO_HEADERS, json=body).json()

@tool
def list_crm_contacts(search: str = "", type: str = "") -> str:
    """List CRM contacts. Optionally filter by search term or type (person/company)."""
    params = {}
    if search: params["search"] = search
    if type:   params["type"]   = type
    return json.dumps(ao_get("crm/contacts", params))

@tool
def list_deals(stage: str = "") -> str:
    """List CRM deals. Optionally filter by stage: new, qualified, proposal, negotiation, won, lost."""
    params = {"stage": stage} if stage else {}
    return json.dumps(ao_get("crm/deals", params))

@tool
def list_projects(status: str = "active") -> str:
    """List projects. Filter by status: planning, active, on_hold, completed, cancelled."""
    return json.dumps(ao_get("projects", {"status": status}))

@tool
def list_overdue_invoices() -> str:
    """List all overdue invoices with amounts."""
    return json.dumps(ao_get("invoice/invoices", {"status": "overdue"}))

@tool
def create_crm_contact(first_name: str, last_name: str, email: str,
                       company: str = "", job_title: str = "") -> str:
    """Create a new CRM contact."""
    body = {"first_name": first_name, "last_name": last_name,
            "email": email, "type": "person"}
    if company:   body["company_name"] = company
    if job_title: body["job_title"]    = job_title
    return json.dumps(ao_post("crm/contacts", body))

@tool
def create_deal(title: str, stage: str = "new", amount: float = 0) -> str:
    """Create a new CRM deal."""
    return json.dumps(ao_post("crm/deals", {"title": title, "stage": stage, "amount": amount}))

tools = [list_crm_contacts, list_deals, list_projects, list_overdue_invoices,
         create_crm_contact, create_deal]

Build the Agent


python
llm    = ChatOpenAI(model="gpt-4o", temperature=0)
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful business assistant with access to AlifOffice data. Always give concise, actionable answers."),
    ("user", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

agent    = create_openai_functions_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Ask questions
executor.invoke({"input": "How many deals do we have in the proposal stage, and what's the total value?"})
executor.invoke({"input": "Are there any overdue invoices? If so, how many and what's the total?"})
executor.invoke({"input": "Create a new contact: John Smith, john@example.com, CTO at ExampleCorp"})

Streaming Responses


python
for chunk in executor.stream({"input": "Give me a summary of all active projects"}):
    if "output" in chunk:
        print(chunk["output"], end="", flush=True)

Deploy as a FastAPI Service


python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Query(BaseModel):
    message: str

@app.post("/ask")
def ask(q: Query):
    result = executor.invoke({"input": q.message})
    return {"answer": result["output"]}

Tip: Use create_openai_tools_agent for parallel tool calls (faster for multi-step queries) instead of create_openai_functions_agent.